/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "libzscanner/error.h"
#include "libzscanner/functions.h"
#include "libknot/endian.h"

const uint8_t digit_to_num[] = {
    ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
    ['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
};

/*
 * Hex transformation:
 *          1        2
 *      12345678 12345678
 * in:    AAAA     BBBB
 * out: AAAABBBB
 */

const uint8_t first_hex_to_num[] = {
    ['0'] = ( 0 * 16), ['6'] = ( 6 * 16), ['C'] = (12 * 16), ['b'] = (11 * 16),
    ['1'] = ( 1 * 16), ['7'] = ( 7 * 16), ['D'] = (13 * 16), ['c'] = (12 * 16),
    ['2'] = ( 2 * 16), ['8'] = ( 8 * 16), ['E'] = (14 * 16), ['d'] = (13 * 16),
    ['3'] = ( 3 * 16), ['9'] = ( 9 * 16), ['F'] = (15 * 16), ['e'] = (14 * 16),
    ['4'] = ( 4 * 16), ['A'] = (10 * 16), ['a'] = (10 * 16), ['f'] = (15 * 16),
    ['5'] = ( 5 * 16), ['B'] = (11 * 16),
};

const uint8_t second_hex_to_num[] = {
    ['0'] =  0, ['4'] =  4, ['8'] =  8, ['C'] = 12, ['a'] = 10, ['d'] = 13,
    ['1'] =  1, ['5'] =  5, ['9'] =  9, ['D'] = 13, ['b'] = 11, ['e'] = 14,
    ['2'] =  2, ['6'] =  6, ['A'] = 10, ['E'] = 14, ['c'] = 12, ['f'] = 15,
    ['3'] =  3, ['7'] =  7, ['B'] = 11, ['F'] = 15,
};

/*
 * Base64 transformation:
 *          1        2        3        4
 *      12345678 12345678 12345678 12345678
 * in:  00AAAAAA 00BBBBBB 00CCCCCC 00DDDDDD
 * out: AAAAAABB BBBBCCCC CCDDDDDD
 */

// 0x3F = 00111111
const uint8_t first_base64_to_num[] = {
    ['A'] = (( 0 & 0x3F) << 2), ['g'] = ((32 & 0x3F) << 2),
    ['B'] = (( 1 & 0x3F) << 2), ['h'] = ((33 & 0x3F) << 2),
    ['C'] = (( 2 & 0x3F) << 2), ['i'] = ((34 & 0x3F) << 2),
    ['D'] = (( 3 & 0x3F) << 2), ['j'] = ((35 & 0x3F) << 2),
    ['E'] = (( 4 & 0x3F) << 2), ['k'] = ((36 & 0x3F) << 2),
    ['F'] = (( 5 & 0x3F) << 2), ['l'] = ((37 & 0x3F) << 2),
    ['G'] = (( 6 & 0x3F) << 2), ['m'] = ((38 & 0x3F) << 2),
    ['H'] = (( 7 & 0x3F) << 2), ['n'] = ((39 & 0x3F) << 2),
    ['I'] = (( 8 & 0x3F) << 2), ['o'] = ((40 & 0x3F) << 2),
    ['J'] = (( 9 & 0x3F) << 2), ['p'] = ((41 & 0x3F) << 2),
    ['K'] = ((10 & 0x3F) << 2), ['q'] = ((42 & 0x3F) << 2),
    ['L'] = ((11 & 0x3F) << 2), ['r'] = ((43 & 0x3F) << 2),
    ['M'] = ((12 & 0x3F) << 2), ['s'] = ((44 & 0x3F) << 2),
    ['N'] = ((13 & 0x3F) << 2), ['t'] = ((45 & 0x3F) << 2),
    ['O'] = ((14 & 0x3F) << 2), ['u'] = ((46 & 0x3F) << 2),
    ['P'] = ((15 & 0x3F) << 2), ['v'] = ((47 & 0x3F) << 2),
    ['Q'] = ((16 & 0x3F) << 2), ['w'] = ((48 & 0x3F) << 2),
    ['R'] = ((17 & 0x3F) << 2), ['x'] = ((49 & 0x3F) << 2),
    ['S'] = ((18 & 0x3F) << 2), ['y'] = ((50 & 0x3F) << 2),
    ['T'] = ((19 & 0x3F) << 2), ['z'] = ((51 & 0x3F) << 2),
    ['U'] = ((20 & 0x3F) << 2), ['0'] = ((52 & 0x3F) << 2),
    ['V'] = ((21 & 0x3F) << 2), ['1'] = ((53 & 0x3F) << 2),
    ['W'] = ((22 & 0x3F) << 2), ['2'] = ((54 & 0x3F) << 2),
    ['X'] = ((23 & 0x3F) << 2), ['3'] = ((55 & 0x3F) << 2),
    ['Y'] = ((24 & 0x3F) << 2), ['4'] = ((56 & 0x3F) << 2),
    ['Z'] = ((25 & 0x3F) << 2), ['5'] = ((57 & 0x3F) << 2),
    ['a'] = ((26 & 0x3F) << 2), ['6'] = ((58 & 0x3F) << 2),
    ['b'] = ((27 & 0x3F) << 2), ['7'] = ((59 & 0x3F) << 2),
    ['c'] = ((28 & 0x3F) << 2), ['8'] = ((60 & 0x3F) << 2),
    ['d'] = ((29 & 0x3F) << 2), ['9'] = ((61 & 0x3F) << 2),
    ['e'] = ((30 & 0x3F) << 2), ['+'] = ((62 & 0x3F) << 2),
    ['f'] = ((31 & 0x3F) << 2), ['/'] = ((63 & 0x3F) << 2),
};

// 0x30 = 00110000
const uint8_t second_left_base64_to_num[] = {
    ['A'] = (( 0 & 0x30) >> 4), ['g'] = ((32 & 0x30) >> 4),
    ['B'] = (( 1 & 0x30) >> 4), ['h'] = ((33 & 0x30) >> 4),
    ['C'] = (( 2 & 0x30) >> 4), ['i'] = ((34 & 0x30) >> 4),
    ['D'] = (( 3 & 0x30) >> 4), ['j'] = ((35 & 0x30) >> 4),
    ['E'] = (( 4 & 0x30) >> 4), ['k'] = ((36 & 0x30) >> 4),
    ['F'] = (( 5 & 0x30) >> 4), ['l'] = ((37 & 0x30) >> 4),
    ['G'] = (( 6 & 0x30) >> 4), ['m'] = ((38 & 0x30) >> 4),
    ['H'] = (( 7 & 0x30) >> 4), ['n'] = ((39 & 0x30) >> 4),
    ['I'] = (( 8 & 0x30) >> 4), ['o'] = ((40 & 0x30) >> 4),
    ['J'] = (( 9 & 0x30) >> 4), ['p'] = ((41 & 0x30) >> 4),
    ['K'] = ((10 & 0x30) >> 4), ['q'] = ((42 & 0x30) >> 4),
    ['L'] = ((11 & 0x30) >> 4), ['r'] = ((43 & 0x30) >> 4),
    ['M'] = ((12 & 0x30) >> 4), ['s'] = ((44 & 0x30) >> 4),
    ['N'] = ((13 & 0x30) >> 4), ['t'] = ((45 & 0x30) >> 4),
    ['O'] = ((14 & 0x30) >> 4), ['u'] = ((46 & 0x30) >> 4),
    ['P'] = ((15 & 0x30) >> 4), ['v'] = ((47 & 0x30) >> 4),
    ['Q'] = ((16 & 0x30) >> 4), ['w'] = ((48 & 0x30) >> 4),
    ['R'] = ((17 & 0x30) >> 4), ['x'] = ((49 & 0x30) >> 4),
    ['S'] = ((18 & 0x30) >> 4), ['y'] = ((50 & 0x30) >> 4),
    ['T'] = ((19 & 0x30) >> 4), ['z'] = ((51 & 0x30) >> 4),
    ['U'] = ((20 & 0x30) >> 4), ['0'] = ((52 & 0x30) >> 4),
    ['V'] = ((21 & 0x30) >> 4), ['1'] = ((53 & 0x30) >> 4),
    ['W'] = ((22 & 0x30) >> 4), ['2'] = ((54 & 0x30) >> 4),
    ['X'] = ((23 & 0x30) >> 4), ['3'] = ((55 & 0x30) >> 4),
    ['Y'] = ((24 & 0x30) >> 4), ['4'] = ((56 & 0x30) >> 4),
    ['Z'] = ((25 & 0x30) >> 4), ['5'] = ((57 & 0x30) >> 4),
    ['a'] = ((26 & 0x30) >> 4), ['6'] = ((58 & 0x30) >> 4),
    ['b'] = ((27 & 0x30) >> 4), ['7'] = ((59 & 0x30) >> 4),
    ['c'] = ((28 & 0x30) >> 4), ['8'] = ((60 & 0x30) >> 4),
    ['d'] = ((29 & 0x30) >> 4), ['9'] = ((61 & 0x30) >> 4),
    ['e'] = ((30 & 0x30) >> 4), ['+'] = ((62 & 0x30) >> 4),
    ['f'] = ((31 & 0x30) >> 4), ['/'] = ((63 & 0x30) >> 4),
};

// 0x0F = 00001111
const uint8_t second_right_base64_to_num[] = {
    ['A'] = (( 0 & 0x0F) << 4), ['g'] = ((32 & 0x0F) << 4),
    ['B'] = (( 1 & 0x0F) << 4), ['h'] = ((33 & 0x0F) << 4),
    ['C'] = (( 2 & 0x0F) << 4), ['i'] = ((34 & 0x0F) << 4),
    ['D'] = (( 3 & 0x0F) << 4), ['j'] = ((35 & 0x0F) << 4),
    ['E'] = (( 4 & 0x0F) << 4), ['k'] = ((36 & 0x0F) << 4),
    ['F'] = (( 5 & 0x0F) << 4), ['l'] = ((37 & 0x0F) << 4),
    ['G'] = (( 6 & 0x0F) << 4), ['m'] = ((38 & 0x0F) << 4),
    ['H'] = (( 7 & 0x0F) << 4), ['n'] = ((39 & 0x0F) << 4),
    ['I'] = (( 8 & 0x0F) << 4), ['o'] = ((40 & 0x0F) << 4),
    ['J'] = (( 9 & 0x0F) << 4), ['p'] = ((41 & 0x0F) << 4),
    ['K'] = ((10 & 0x0F) << 4), ['q'] = ((42 & 0x0F) << 4),
    ['L'] = ((11 & 0x0F) << 4), ['r'] = ((43 & 0x0F) << 4),
    ['M'] = ((12 & 0x0F) << 4), ['s'] = ((44 & 0x0F) << 4),
    ['N'] = ((13 & 0x0F) << 4), ['t'] = ((45 & 0x0F) << 4),
    ['O'] = ((14 & 0x0F) << 4), ['u'] = ((46 & 0x0F) << 4),
    ['P'] = ((15 & 0x0F) << 4), ['v'] = ((47 & 0x0F) << 4),
    ['Q'] = ((16 & 0x0F) << 4), ['w'] = ((48 & 0x0F) << 4),
    ['R'] = ((17 & 0x0F) << 4), ['x'] = ((49 & 0x0F) << 4),
    ['S'] = ((18 & 0x0F) << 4), ['y'] = ((50 & 0x0F) << 4),
    ['T'] = ((19 & 0x0F) << 4), ['z'] = ((51 & 0x0F) << 4),
    ['U'] = ((20 & 0x0F) << 4), ['0'] = ((52 & 0x0F) << 4),
    ['V'] = ((21 & 0x0F) << 4), ['1'] = ((53 & 0x0F) << 4),
    ['W'] = ((22 & 0x0F) << 4), ['2'] = ((54 & 0x0F) << 4),
    ['X'] = ((23 & 0x0F) << 4), ['3'] = ((55 & 0x0F) << 4),
    ['Y'] = ((24 & 0x0F) << 4), ['4'] = ((56 & 0x0F) << 4),
    ['Z'] = ((25 & 0x0F) << 4), ['5'] = ((57 & 0x0F) << 4),
    ['a'] = ((26 & 0x0F) << 4), ['6'] = ((58 & 0x0F) << 4),
    ['b'] = ((27 & 0x0F) << 4), ['7'] = ((59 & 0x0F) << 4),
    ['c'] = ((28 & 0x0F) << 4), ['8'] = ((60 & 0x0F) << 4),
    ['d'] = ((29 & 0x0F) << 4), ['9'] = ((61 & 0x0F) << 4),
    ['e'] = ((30 & 0x0F) << 4), ['+'] = ((62 & 0x0F) << 4),
    ['f'] = ((31 & 0x0F) << 4), ['/'] = ((63 & 0x0F) << 4),
};

// 0x3C = 00111100
const uint8_t third_left_base64_to_num[] = {
    ['A'] = (( 0 & 0x3C) >> 2), ['g'] = ((32 & 0x3C) >> 2),
    ['B'] = (( 1 & 0x3C) >> 2), ['h'] = ((33 & 0x3C) >> 2),
    ['C'] = (( 2 & 0x3C) >> 2), ['i'] = ((34 & 0x3C) >> 2),
    ['D'] = (( 3 & 0x3C) >> 2), ['j'] = ((35 & 0x3C) >> 2),
    ['E'] = (( 4 & 0x3C) >> 2), ['k'] = ((36 & 0x3C) >> 2),
    ['F'] = (( 5 & 0x3C) >> 2), ['l'] = ((37 & 0x3C) >> 2),
    ['G'] = (( 6 & 0x3C) >> 2), ['m'] = ((38 & 0x3C) >> 2),
    ['H'] = (( 7 & 0x3C) >> 2), ['n'] = ((39 & 0x3C) >> 2),
    ['I'] = (( 8 & 0x3C) >> 2), ['o'] = ((40 & 0x3C) >> 2),
    ['J'] = (( 9 & 0x3C) >> 2), ['p'] = ((41 & 0x3C) >> 2),
    ['K'] = ((10 & 0x3C) >> 2), ['q'] = ((42 & 0x3C) >> 2),
    ['L'] = ((11 & 0x3C) >> 2), ['r'] = ((43 & 0x3C) >> 2),
    ['M'] = ((12 & 0x3C) >> 2), ['s'] = ((44 & 0x3C) >> 2),
    ['N'] = ((13 & 0x3C) >> 2), ['t'] = ((45 & 0x3C) >> 2),
    ['O'] = ((14 & 0x3C) >> 2), ['u'] = ((46 & 0x3C) >> 2),
    ['P'] = ((15 & 0x3C) >> 2), ['v'] = ((47 & 0x3C) >> 2),
    ['Q'] = ((16 & 0x3C) >> 2), ['w'] = ((48 & 0x3C) >> 2),
    ['R'] = ((17 & 0x3C) >> 2), ['x'] = ((49 & 0x3C) >> 2),
    ['S'] = ((18 & 0x3C) >> 2), ['y'] = ((50 & 0x3C) >> 2),
    ['T'] = ((19 & 0x3C) >> 2), ['z'] = ((51 & 0x3C) >> 2),
    ['U'] = ((20 & 0x3C) >> 2), ['0'] = ((52 & 0x3C) >> 2),
    ['V'] = ((21 & 0x3C) >> 2), ['1'] = ((53 & 0x3C) >> 2),
    ['W'] = ((22 & 0x3C) >> 2), ['2'] = ((54 & 0x3C) >> 2),
    ['X'] = ((23 & 0x3C) >> 2), ['3'] = ((55 & 0x3C) >> 2),
    ['Y'] = ((24 & 0x3C) >> 2), ['4'] = ((56 & 0x3C) >> 2),
    ['Z'] = ((25 & 0x3C) >> 2), ['5'] = ((57 & 0x3C) >> 2),
    ['a'] = ((26 & 0x3C) >> 2), ['6'] = ((58 & 0x3C) >> 2),
    ['b'] = ((27 & 0x3C) >> 2), ['7'] = ((59 & 0x3C) >> 2),
    ['c'] = ((28 & 0x3C) >> 2), ['8'] = ((60 & 0x3C) >> 2),
    ['d'] = ((29 & 0x3C) >> 2), ['9'] = ((61 & 0x3C) >> 2),
    ['e'] = ((30 & 0x3C) >> 2), ['+'] = ((62 & 0x3C) >> 2),
    ['f'] = ((31 & 0x3C) >> 2), ['/'] = ((63 & 0x3C) >> 2),
};

// 0x03 = 00000011
const uint8_t third_right_base64_to_num[] = {
    ['A'] = (( 0 & 0x03) << 6), ['g'] = ((32 & 0x03) << 6),
    ['B'] = (( 1 & 0x03) << 6), ['h'] = ((33 & 0x03) << 6),
    ['C'] = (( 2 & 0x03) << 6), ['i'] = ((34 & 0x03) << 6),
    ['D'] = (( 3 & 0x03) << 6), ['j'] = ((35 & 0x03) << 6),
    ['E'] = (( 4 & 0x03) << 6), ['k'] = ((36 & 0x03) << 6),
    ['F'] = (( 5 & 0x03) << 6), ['l'] = ((37 & 0x03) << 6),
    ['G'] = (( 6 & 0x03) << 6), ['m'] = ((38 & 0x03) << 6),
    ['H'] = (( 7 & 0x03) << 6), ['n'] = ((39 & 0x03) << 6),
    ['I'] = (( 8 & 0x03) << 6), ['o'] = ((40 & 0x03) << 6),
    ['J'] = (( 9 & 0x03) << 6), ['p'] = ((41 & 0x03) << 6),
    ['K'] = ((10 & 0x03) << 6), ['q'] = ((42 & 0x03) << 6),
    ['L'] = ((11 & 0x03) << 6), ['r'] = ((43 & 0x03) << 6),
    ['M'] = ((12 & 0x03) << 6), ['s'] = ((44 & 0x03) << 6),
    ['N'] = ((13 & 0x03) << 6), ['t'] = ((45 & 0x03) << 6),
    ['O'] = ((14 & 0x03) << 6), ['u'] = ((46 & 0x03) << 6),
    ['P'] = ((15 & 0x03) << 6), ['v'] = ((47 & 0x03) << 6),
    ['Q'] = ((16 & 0x03) << 6), ['w'] = ((48 & 0x03) << 6),
    ['R'] = ((17 & 0x03) << 6), ['x'] = ((49 & 0x03) << 6),
    ['S'] = ((18 & 0x03) << 6), ['y'] = ((50 & 0x03) << 6),
    ['T'] = ((19 & 0x03) << 6), ['z'] = ((51 & 0x03) << 6),
    ['U'] = ((20 & 0x03) << 6), ['0'] = ((52 & 0x03) << 6),
    ['V'] = ((21 & 0x03) << 6), ['1'] = ((53 & 0x03) << 6),
    ['W'] = ((22 & 0x03) << 6), ['2'] = ((54 & 0x03) << 6),
    ['X'] = ((23 & 0x03) << 6), ['3'] = ((55 & 0x03) << 6),
    ['Y'] = ((24 & 0x03) << 6), ['4'] = ((56 & 0x03) << 6),
    ['Z'] = ((25 & 0x03) << 6), ['5'] = ((57 & 0x03) << 6),
    ['a'] = ((26 & 0x03) << 6), ['6'] = ((58 & 0x03) << 6),
    ['b'] = ((27 & 0x03) << 6), ['7'] = ((59 & 0x03) << 6),
    ['c'] = ((28 & 0x03) << 6), ['8'] = ((60 & 0x03) << 6),
    ['d'] = ((29 & 0x03) << 6), ['9'] = ((61 & 0x03) << 6),
    ['e'] = ((30 & 0x03) << 6), ['+'] = ((62 & 0x03) << 6),
    ['f'] = ((31 & 0x03) << 6), ['/'] = ((63 & 0x03) << 6),
};

// 0x3F = 00111111
const uint8_t fourth_base64_to_num[] = {
    ['A'] = (( 0 & 0x3F) << 0), ['g'] = ((32 & 0x3F) << 0),
    ['B'] = (( 1 & 0x3F) << 0), ['h'] = ((33 & 0x3F) << 0),
    ['C'] = (( 2 & 0x3F) << 0), ['i'] = ((34 & 0x3F) << 0),
    ['D'] = (( 3 & 0x3F) << 0), ['j'] = ((35 & 0x3F) << 0),
    ['E'] = (( 4 & 0x3F) << 0), ['k'] = ((36 & 0x3F) << 0),
    ['F'] = (( 5 & 0x3F) << 0), ['l'] = ((37 & 0x3F) << 0),
    ['G'] = (( 6 & 0x3F) << 0), ['m'] = ((38 & 0x3F) << 0),
    ['H'] = (( 7 & 0x3F) << 0), ['n'] = ((39 & 0x3F) << 0),
    ['I'] = (( 8 & 0x3F) << 0), ['o'] = ((40 & 0x3F) << 0),
    ['J'] = (( 9 & 0x3F) << 0), ['p'] = ((41 & 0x3F) << 0),
    ['K'] = ((10 & 0x3F) << 0), ['q'] = ((42 & 0x3F) << 0),
    ['L'] = ((11 & 0x3F) << 0), ['r'] = ((43 & 0x3F) << 0),
    ['M'] = ((12 & 0x3F) << 0), ['s'] = ((44 & 0x3F) << 0),
    ['N'] = ((13 & 0x3F) << 0), ['t'] = ((45 & 0x3F) << 0),
    ['O'] = ((14 & 0x3F) << 0), ['u'] = ((46 & 0x3F) << 0),
    ['P'] = ((15 & 0x3F) << 0), ['v'] = ((47 & 0x3F) << 0),
    ['Q'] = ((16 & 0x3F) << 0), ['w'] = ((48 & 0x3F) << 0),
    ['R'] = ((17 & 0x3F) << 0), ['x'] = ((49 & 0x3F) << 0),
    ['S'] = ((18 & 0x3F) << 0), ['y'] = ((50 & 0x3F) << 0),
    ['T'] = ((19 & 0x3F) << 0), ['z'] = ((51 & 0x3F) << 0),
    ['U'] = ((20 & 0x3F) << 0), ['0'] = ((52 & 0x3F) << 0),
    ['V'] = ((21 & 0x3F) << 0), ['1'] = ((53 & 0x3F) << 0),
    ['W'] = ((22 & 0x3F) << 0), ['2'] = ((54 & 0x3F) << 0),
    ['X'] = ((23 & 0x3F) << 0), ['3'] = ((55 & 0x3F) << 0),
    ['Y'] = ((24 & 0x3F) << 0), ['4'] = ((56 & 0x3F) << 0),
    ['Z'] = ((25 & 0x3F) << 0), ['5'] = ((57 & 0x3F) << 0),
    ['a'] = ((26 & 0x3F) << 0), ['6'] = ((58 & 0x3F) << 0),
    ['b'] = ((27 & 0x3F) << 0), ['7'] = ((59 & 0x3F) << 0),
    ['c'] = ((28 & 0x3F) << 0), ['8'] = ((60 & 0x3F) << 0),
    ['d'] = ((29 & 0x3F) << 0), ['9'] = ((61 & 0x3F) << 0),
    ['e'] = ((30 & 0x3F) << 0), ['+'] = ((62 & 0x3F) << 0),
    ['f'] = ((31 & 0x3F) << 0), ['/'] = ((63 & 0x3F) << 0),
};

/*
 * Base32hex transformation (with lower-case):
 *          1        2        3        4        5        6        7        8
 *      12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678
 * in:  000AAAAA 000BBBBB 000CCCCC 000DDDDD 000EEEEE 000FFFFF 000GGGGG 000HHHHH
 * out  AAAAABBB BBCCCCCD DDDDEEEE EFFFFFGG GGGHHHHH
 */

// 0x1F = 00011111
const uint8_t first_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1F) << 3), ['R'] = ((27 & 0x1F) << 3),
    ['1'] = (( 1 & 0x1F) << 3), ['S'] = ((28 & 0x1F) << 3),
    ['2'] = (( 2 & 0x1F) << 3), ['T'] = ((29 & 0x1F) << 3),
    ['3'] = (( 3 & 0x1F) << 3), ['U'] = ((30 & 0x1F) << 3),
    ['4'] = (( 4 & 0x1F) << 3), ['V'] = ((31 & 0x1F) << 3),
    ['5'] = (( 5 & 0x1F) << 3), ['a'] = ((10 & 0x1F) << 3),
    ['6'] = (( 6 & 0x1F) << 3), ['b'] = ((11 & 0x1F) << 3),
    ['7'] = (( 7 & 0x1F) << 3), ['c'] = ((12 & 0x1F) << 3),
    ['8'] = (( 8 & 0x1F) << 3), ['d'] = ((13 & 0x1F) << 3),
    ['9'] = (( 9 & 0x1F) << 3), ['e'] = ((14 & 0x1F) << 3),
    ['A'] = ((10 & 0x1F) << 3), ['f'] = ((15 & 0x1F) << 3),
    ['B'] = ((11 & 0x1F) << 3), ['g'] = ((16 & 0x1F) << 3),
    ['C'] = ((12 & 0x1F) << 3), ['h'] = ((17 & 0x1F) << 3),
    ['D'] = ((13 & 0x1F) << 3), ['i'] = ((18 & 0x1F) << 3),
    ['E'] = ((14 & 0x1F) << 3), ['j'] = ((19 & 0x1F) << 3),
    ['F'] = ((15 & 0x1F) << 3), ['k'] = ((20 & 0x1F) << 3),
    ['G'] = ((16 & 0x1F) << 3), ['l'] = ((21 & 0x1F) << 3),
    ['H'] = ((17 & 0x1F) << 3), ['m'] = ((22 & 0x1F) << 3),
    ['I'] = ((18 & 0x1F) << 3), ['n'] = ((23 & 0x1F) << 3),
    ['J'] = ((19 & 0x1F) << 3), ['o'] = ((24 & 0x1F) << 3),
    ['K'] = ((20 & 0x1F) << 3), ['p'] = ((25 & 0x1F) << 3),
    ['L'] = ((21 & 0x1F) << 3), ['q'] = ((26 & 0x1F) << 3),
    ['M'] = ((22 & 0x1F) << 3), ['r'] = ((27 & 0x1F) << 3),
    ['N'] = ((23 & 0x1F) << 3), ['s'] = ((28 & 0x1F) << 3),
    ['O'] = ((24 & 0x1F) << 3), ['t'] = ((29 & 0x1F) << 3),
    ['P'] = ((25 & 0x1F) << 3), ['u'] = ((30 & 0x1F) << 3),
    ['Q'] = ((26 & 0x1F) << 3), ['v'] = ((31 & 0x1F) << 3),
};

// 0x1C = 00011100
const uint8_t second_left_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1C) >> 2), ['R'] = ((27 & 0x1C) >> 2),
    ['1'] = (( 1 & 0x1C) >> 2), ['S'] = ((28 & 0x1C) >> 2),
    ['2'] = (( 2 & 0x1C) >> 2), ['T'] = ((29 & 0x1C) >> 2),
    ['3'] = (( 3 & 0x1C) >> 2), ['U'] = ((30 & 0x1C) >> 2),
    ['4'] = (( 4 & 0x1C) >> 2), ['V'] = ((31 & 0x1C) >> 2),
    ['5'] = (( 5 & 0x1C) >> 2), ['a'] = ((10 & 0x1C) >> 2),
    ['6'] = (( 6 & 0x1C) >> 2), ['b'] = ((11 & 0x1C) >> 2),
    ['7'] = (( 7 & 0x1C) >> 2), ['c'] = ((12 & 0x1C) >> 2),
    ['8'] = (( 8 & 0x1C) >> 2), ['d'] = ((13 & 0x1C) >> 2),
    ['9'] = (( 9 & 0x1C) >> 2), ['e'] = ((14 & 0x1C) >> 2),
    ['A'] = ((10 & 0x1C) >> 2), ['f'] = ((15 & 0x1C) >> 2),
    ['B'] = ((11 & 0x1C) >> 2), ['g'] = ((16 & 0x1C) >> 2),
    ['C'] = ((12 & 0x1C) >> 2), ['h'] = ((17 & 0x1C) >> 2),
    ['D'] = ((13 & 0x1C) >> 2), ['i'] = ((18 & 0x1C) >> 2),
    ['E'] = ((14 & 0x1C) >> 2), ['j'] = ((19 & 0x1C) >> 2),
    ['F'] = ((15 & 0x1C) >> 2), ['k'] = ((20 & 0x1C) >> 2),
    ['G'] = ((16 & 0x1C) >> 2), ['l'] = ((21 & 0x1C) >> 2),
    ['H'] = ((17 & 0x1C) >> 2), ['m'] = ((22 & 0x1C) >> 2),
    ['I'] = ((18 & 0x1C) >> 2), ['n'] = ((23 & 0x1C) >> 2),
    ['J'] = ((19 & 0x1C) >> 2), ['o'] = ((24 & 0x1C) >> 2),
    ['K'] = ((20 & 0x1C) >> 2), ['p'] = ((25 & 0x1C) >> 2),
    ['L'] = ((21 & 0x1C) >> 2), ['q'] = ((26 & 0x1C) >> 2),
    ['M'] = ((22 & 0x1C) >> 2), ['r'] = ((27 & 0x1C) >> 2),
    ['N'] = ((23 & 0x1C) >> 2), ['s'] = ((28 & 0x1C) >> 2),
    ['O'] = ((24 & 0x1C) >> 2), ['t'] = ((29 & 0x1C) >> 2),
    ['P'] = ((25 & 0x1C) >> 2), ['u'] = ((30 & 0x1C) >> 2),
    ['Q'] = ((26 & 0x1C) >> 2), ['v'] = ((31 & 0x1C) >> 2),
};

// 0x03 = 00000011
const uint8_t second_right_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x03) << 6), ['R'] = ((27 & 0x03) << 6),
    ['1'] = (( 1 & 0x03) << 6), ['S'] = ((28 & 0x03) << 6),
    ['2'] = (( 2 & 0x03) << 6), ['T'] = ((29 & 0x03) << 6),
    ['3'] = (( 3 & 0x03) << 6), ['U'] = ((30 & 0x03) << 6),
    ['4'] = (( 4 & 0x03) << 6), ['V'] = ((31 & 0x03) << 6),
    ['5'] = (( 5 & 0x03) << 6), ['a'] = ((10 & 0x03) << 6),
    ['6'] = (( 6 & 0x03) << 6), ['b'] = ((11 & 0x03) << 6),
    ['7'] = (( 7 & 0x03) << 6), ['c'] = ((12 & 0x03) << 6),
    ['8'] = (( 8 & 0x03) << 6), ['d'] = ((13 & 0x03) << 6),
    ['9'] = (( 9 & 0x03) << 6), ['e'] = ((14 & 0x03) << 6),
    ['A'] = ((10 & 0x03) << 6), ['f'] = ((15 & 0x03) << 6),
    ['B'] = ((11 & 0x03) << 6), ['g'] = ((16 & 0x03) << 6),
    ['C'] = ((12 & 0x03) << 6), ['h'] = ((17 & 0x03) << 6),
    ['D'] = ((13 & 0x03) << 6), ['i'] = ((18 & 0x03) << 6),
    ['E'] = ((14 & 0x03) << 6), ['j'] = ((19 & 0x03) << 6),
    ['F'] = ((15 & 0x03) << 6), ['k'] = ((20 & 0x03) << 6),
    ['G'] = ((16 & 0x03) << 6), ['l'] = ((21 & 0x03) << 6),
    ['H'] = ((17 & 0x03) << 6), ['m'] = ((22 & 0x03) << 6),
    ['I'] = ((18 & 0x03) << 6), ['n'] = ((23 & 0x03) << 6),
    ['J'] = ((19 & 0x03) << 6), ['o'] = ((24 & 0x03) << 6),
    ['K'] = ((20 & 0x03) << 6), ['p'] = ((25 & 0x03) << 6),
    ['L'] = ((21 & 0x03) << 6), ['q'] = ((26 & 0x03) << 6),
    ['M'] = ((22 & 0x03) << 6), ['r'] = ((27 & 0x03) << 6),
    ['N'] = ((23 & 0x03) << 6), ['s'] = ((28 & 0x03) << 6),
    ['O'] = ((24 & 0x03) << 6), ['t'] = ((29 & 0x03) << 6),
    ['P'] = ((25 & 0x03) << 6), ['u'] = ((30 & 0x03) << 6),
    ['Q'] = ((26 & 0x03) << 6), ['v'] = ((31 & 0x03) << 6),
};

// 0x1F = 00011111
const uint8_t third_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1F) << 1), ['R'] = ((27 & 0x1F) << 1),
    ['1'] = (( 1 & 0x1F) << 1), ['S'] = ((28 & 0x1F) << 1),
    ['2'] = (( 2 & 0x1F) << 1), ['T'] = ((29 & 0x1F) << 1),
    ['3'] = (( 3 & 0x1F) << 1), ['U'] = ((30 & 0x1F) << 1),
    ['4'] = (( 4 & 0x1F) << 1), ['V'] = ((31 & 0x1F) << 1),
    ['5'] = (( 5 & 0x1F) << 1), ['a'] = ((10 & 0x1F) << 1),
    ['6'] = (( 6 & 0x1F) << 1), ['b'] = ((11 & 0x1F) << 1),
    ['7'] = (( 7 & 0x1F) << 1), ['c'] = ((12 & 0x1F) << 1),
    ['8'] = (( 8 & 0x1F) << 1), ['d'] = ((13 & 0x1F) << 1),
    ['9'] = (( 9 & 0x1F) << 1), ['e'] = ((14 & 0x1F) << 1),
    ['A'] = ((10 & 0x1F) << 1), ['f'] = ((15 & 0x1F) << 1),
    ['B'] = ((11 & 0x1F) << 1), ['g'] = ((16 & 0x1F) << 1),
    ['C'] = ((12 & 0x1F) << 1), ['h'] = ((17 & 0x1F) << 1),
    ['D'] = ((13 & 0x1F) << 1), ['i'] = ((18 & 0x1F) << 1),
    ['E'] = ((14 & 0x1F) << 1), ['j'] = ((19 & 0x1F) << 1),
    ['F'] = ((15 & 0x1F) << 1), ['k'] = ((20 & 0x1F) << 1),
    ['G'] = ((16 & 0x1F) << 1), ['l'] = ((21 & 0x1F) << 1),
    ['H'] = ((17 & 0x1F) << 1), ['m'] = ((22 & 0x1F) << 1),
    ['I'] = ((18 & 0x1F) << 1), ['n'] = ((23 & 0x1F) << 1),
    ['J'] = ((19 & 0x1F) << 1), ['o'] = ((24 & 0x1F) << 1),
    ['K'] = ((20 & 0x1F) << 1), ['p'] = ((25 & 0x1F) << 1),
    ['L'] = ((21 & 0x1F) << 1), ['q'] = ((26 & 0x1F) << 1),
    ['M'] = ((22 & 0x1F) << 1), ['r'] = ((27 & 0x1F) << 1),
    ['N'] = ((23 & 0x1F) << 1), ['s'] = ((28 & 0x1F) << 1),
    ['O'] = ((24 & 0x1F) << 1), ['t'] = ((29 & 0x1F) << 1),
    ['P'] = ((25 & 0x1F) << 1), ['u'] = ((30 & 0x1F) << 1),
    ['Q'] = ((26 & 0x1F) << 1), ['v'] = ((31 & 0x1F) << 1),
};

// 0x10 = 00010000
const uint8_t fourth_left_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x10) >> 4), ['R'] = ((27 & 0x10) >> 4),
    ['1'] = (( 1 & 0x10) >> 4), ['S'] = ((28 & 0x10) >> 4),
    ['2'] = (( 2 & 0x10) >> 4), ['T'] = ((29 & 0x10) >> 4),
    ['3'] = (( 3 & 0x10) >> 4), ['U'] = ((30 & 0x10) >> 4),
    ['4'] = (( 4 & 0x10) >> 4), ['V'] = ((31 & 0x10) >> 4),
    ['5'] = (( 5 & 0x10) >> 4), ['a'] = ((10 & 0x10) >> 4),
    ['6'] = (( 6 & 0x10) >> 4), ['b'] = ((11 & 0x10) >> 4),
    ['7'] = (( 7 & 0x10) >> 4), ['c'] = ((12 & 0x10) >> 4),
    ['8'] = (( 8 & 0x10) >> 4), ['d'] = ((13 & 0x10) >> 4),
    ['9'] = (( 9 & 0x10) >> 4), ['e'] = ((14 & 0x10) >> 4),
    ['A'] = ((10 & 0x10) >> 4), ['f'] = ((15 & 0x10) >> 4),
    ['B'] = ((11 & 0x10) >> 4), ['g'] = ((16 & 0x10) >> 4),
    ['C'] = ((12 & 0x10) >> 4), ['h'] = ((17 & 0x10) >> 4),
    ['D'] = ((13 & 0x10) >> 4), ['i'] = ((18 & 0x10) >> 4),
    ['E'] = ((14 & 0x10) >> 4), ['j'] = ((19 & 0x10) >> 4),
    ['F'] = ((15 & 0x10) >> 4), ['k'] = ((20 & 0x10) >> 4),
    ['G'] = ((16 & 0x10) >> 4), ['l'] = ((21 & 0x10) >> 4),
    ['H'] = ((17 & 0x10) >> 4), ['m'] = ((22 & 0x10) >> 4),
    ['I'] = ((18 & 0x10) >> 4), ['n'] = ((23 & 0x10) >> 4),
    ['J'] = ((19 & 0x10) >> 4), ['o'] = ((24 & 0x10) >> 4),
    ['K'] = ((20 & 0x10) >> 4), ['p'] = ((25 & 0x10) >> 4),
    ['L'] = ((21 & 0x10) >> 4), ['q'] = ((26 & 0x10) >> 4),
    ['M'] = ((22 & 0x10) >> 4), ['r'] = ((27 & 0x10) >> 4),
    ['N'] = ((23 & 0x10) >> 4), ['s'] = ((28 & 0x10) >> 4),
    ['O'] = ((24 & 0x10) >> 4), ['t'] = ((29 & 0x10) >> 4),
    ['P'] = ((25 & 0x10) >> 4), ['u'] = ((30 & 0x10) >> 4),
    ['Q'] = ((26 & 0x10) >> 4), ['v'] = ((31 & 0x10) >> 4),
};

// 0x0F = 00001111
const uint8_t fourth_right_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x0F) << 4), ['R'] = ((27 & 0x0F) << 4),
    ['1'] = (( 1 & 0x0F) << 4), ['S'] = ((28 & 0x0F) << 4),
    ['2'] = (( 2 & 0x0F) << 4), ['T'] = ((29 & 0x0F) << 4),
    ['3'] = (( 3 & 0x0F) << 4), ['U'] = ((30 & 0x0F) << 4),
    ['4'] = (( 4 & 0x0F) << 4), ['V'] = ((31 & 0x0F) << 4),
    ['5'] = (( 5 & 0x0F) << 4), ['a'] = ((10 & 0x0F) << 4),
    ['6'] = (( 6 & 0x0F) << 4), ['b'] = ((11 & 0x0F) << 4),
    ['7'] = (( 7 & 0x0F) << 4), ['c'] = ((12 & 0x0F) << 4),
    ['8'] = (( 8 & 0x0F) << 4), ['d'] = ((13 & 0x0F) << 4),
    ['9'] = (( 9 & 0x0F) << 4), ['e'] = ((14 & 0x0F) << 4),
    ['A'] = ((10 & 0x0F) << 4), ['f'] = ((15 & 0x0F) << 4),
    ['B'] = ((11 & 0x0F) << 4), ['g'] = ((16 & 0x0F) << 4),
    ['C'] = ((12 & 0x0F) << 4), ['h'] = ((17 & 0x0F) << 4),
    ['D'] = ((13 & 0x0F) << 4), ['i'] = ((18 & 0x0F) << 4),
    ['E'] = ((14 & 0x0F) << 4), ['j'] = ((19 & 0x0F) << 4),
    ['F'] = ((15 & 0x0F) << 4), ['k'] = ((20 & 0x0F) << 4),
    ['G'] = ((16 & 0x0F) << 4), ['l'] = ((21 & 0x0F) << 4),
    ['H'] = ((17 & 0x0F) << 4), ['m'] = ((22 & 0x0F) << 4),
    ['I'] = ((18 & 0x0F) << 4), ['n'] = ((23 & 0x0F) << 4),
    ['J'] = ((19 & 0x0F) << 4), ['o'] = ((24 & 0x0F) << 4),
    ['K'] = ((20 & 0x0F) << 4), ['p'] = ((25 & 0x0F) << 4),
    ['L'] = ((21 & 0x0F) << 4), ['q'] = ((26 & 0x0F) << 4),
    ['M'] = ((22 & 0x0F) << 4), ['r'] = ((27 & 0x0F) << 4),
    ['N'] = ((23 & 0x0F) << 4), ['s'] = ((28 & 0x0F) << 4),
    ['O'] = ((24 & 0x0F) << 4), ['t'] = ((29 & 0x0F) << 4),
    ['P'] = ((25 & 0x0F) << 4), ['u'] = ((30 & 0x0F) << 4),
    ['Q'] = ((26 & 0x0F) << 4), ['v'] = ((31 & 0x0F) << 4),
};

// 0x1E = 00011110
const uint8_t fifth_left_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1E) >> 1), ['R'] = ((27 & 0x1E) >> 1),
    ['1'] = (( 1 & 0x1E) >> 1), ['S'] = ((28 & 0x1E) >> 1),
    ['2'] = (( 2 & 0x1E) >> 1), ['T'] = ((29 & 0x1E) >> 1),
    ['3'] = (( 3 & 0x1E) >> 1), ['U'] = ((30 & 0x1E) >> 1),
    ['4'] = (( 4 & 0x1E) >> 1), ['V'] = ((31 & 0x1E) >> 1),
    ['5'] = (( 5 & 0x1E) >> 1), ['a'] = ((10 & 0x1E) >> 1),
    ['6'] = (( 6 & 0x1E) >> 1), ['b'] = ((11 & 0x1E) >> 1),
    ['7'] = (( 7 & 0x1E) >> 1), ['c'] = ((12 & 0x1E) >> 1),
    ['8'] = (( 8 & 0x1E) >> 1), ['d'] = ((13 & 0x1E) >> 1),
    ['9'] = (( 9 & 0x1E) >> 1), ['e'] = ((14 & 0x1E) >> 1),
    ['A'] = ((10 & 0x1E) >> 1), ['f'] = ((15 & 0x1E) >> 1),
    ['B'] = ((11 & 0x1E) >> 1), ['g'] = ((16 & 0x1E) >> 1),
    ['C'] = ((12 & 0x1E) >> 1), ['h'] = ((17 & 0x1E) >> 1),
    ['D'] = ((13 & 0x1E) >> 1), ['i'] = ((18 & 0x1E) >> 1),
    ['E'] = ((14 & 0x1E) >> 1), ['j'] = ((19 & 0x1E) >> 1),
    ['F'] = ((15 & 0x1E) >> 1), ['k'] = ((20 & 0x1E) >> 1),
    ['G'] = ((16 & 0x1E) >> 1), ['l'] = ((21 & 0x1E) >> 1),
    ['H'] = ((17 & 0x1E) >> 1), ['m'] = ((22 & 0x1E) >> 1),
    ['I'] = ((18 & 0x1E) >> 1), ['n'] = ((23 & 0x1E) >> 1),
    ['J'] = ((19 & 0x1E) >> 1), ['o'] = ((24 & 0x1E) >> 1),
    ['K'] = ((20 & 0x1E) >> 1), ['p'] = ((25 & 0x1E) >> 1),
    ['L'] = ((21 & 0x1E) >> 1), ['q'] = ((26 & 0x1E) >> 1),
    ['M'] = ((22 & 0x1E) >> 1), ['r'] = ((27 & 0x1E) >> 1),
    ['N'] = ((23 & 0x1E) >> 1), ['s'] = ((28 & 0x1E) >> 1),
    ['O'] = ((24 & 0x1E) >> 1), ['t'] = ((29 & 0x1E) >> 1),
    ['P'] = ((25 & 0x1E) >> 1), ['u'] = ((30 & 0x1E) >> 1),
    ['Q'] = ((26 & 0x1E) >> 1), ['v'] = ((31 & 0x1E) >> 1),
};

// 0x01 = 00000001
const uint8_t fifth_right_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x01) << 7), ['R'] = ((27 & 0x01) << 7),
    ['1'] = (( 1 & 0x01) << 7), ['S'] = ((28 & 0x01) << 7),
    ['2'] = (( 2 & 0x01) << 7), ['T'] = ((29 & 0x01) << 7),
    ['3'] = (( 3 & 0x01) << 7), ['U'] = ((30 & 0x01) << 7),
    ['4'] = (( 4 & 0x01) << 7), ['V'] = ((31 & 0x01) << 7),
    ['5'] = (( 5 & 0x01) << 7), ['a'] = ((10 & 0x01) << 7),
    ['6'] = (( 6 & 0x01) << 7), ['b'] = ((11 & 0x01) << 7),
    ['7'] = (( 7 & 0x01) << 7), ['c'] = ((12 & 0x01) << 7),
    ['8'] = (( 8 & 0x01) << 7), ['d'] = ((13 & 0x01) << 7),
    ['9'] = (( 9 & 0x01) << 7), ['e'] = ((14 & 0x01) << 7),
    ['A'] = ((10 & 0x01) << 7), ['f'] = ((15 & 0x01) << 7),
    ['B'] = ((11 & 0x01) << 7), ['g'] = ((16 & 0x01) << 7),
    ['C'] = ((12 & 0x01) << 7), ['h'] = ((17 & 0x01) << 7),
    ['D'] = ((13 & 0x01) << 7), ['i'] = ((18 & 0x01) << 7),
    ['E'] = ((14 & 0x01) << 7), ['j'] = ((19 & 0x01) << 7),
    ['F'] = ((15 & 0x01) << 7), ['k'] = ((20 & 0x01) << 7),
    ['G'] = ((16 & 0x01) << 7), ['l'] = ((21 & 0x01) << 7),
    ['H'] = ((17 & 0x01) << 7), ['m'] = ((22 & 0x01) << 7),
    ['I'] = ((18 & 0x01) << 7), ['n'] = ((23 & 0x01) << 7),
    ['J'] = ((19 & 0x01) << 7), ['o'] = ((24 & 0x01) << 7),
    ['K'] = ((20 & 0x01) << 7), ['p'] = ((25 & 0x01) << 7),
    ['L'] = ((21 & 0x01) << 7), ['q'] = ((26 & 0x01) << 7),
    ['M'] = ((22 & 0x01) << 7), ['r'] = ((27 & 0x01) << 7),
    ['N'] = ((23 & 0x01) << 7), ['s'] = ((28 & 0x01) << 7),
    ['O'] = ((24 & 0x01) << 7), ['t'] = ((29 & 0x01) << 7),
    ['P'] = ((25 & 0x01) << 7), ['u'] = ((30 & 0x01) << 7),
    ['Q'] = ((26 & 0x01) << 7), ['v'] = ((31 & 0x01) << 7),
};

// 0x1F = 00011111
const uint8_t sixth_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1F) << 2), ['R'] = ((27 & 0x1F) << 2),
    ['1'] = (( 1 & 0x1F) << 2), ['S'] = ((28 & 0x1F) << 2),
    ['2'] = (( 2 & 0x1F) << 2), ['T'] = ((29 & 0x1F) << 2),
    ['3'] = (( 3 & 0x1F) << 2), ['U'] = ((30 & 0x1F) << 2),
    ['4'] = (( 4 & 0x1F) << 2), ['V'] = ((31 & 0x1F) << 2),
    ['5'] = (( 5 & 0x1F) << 2), ['a'] = ((10 & 0x1F) << 2),
    ['6'] = (( 6 & 0x1F) << 2), ['b'] = ((11 & 0x1F) << 2),
    ['7'] = (( 7 & 0x1F) << 2), ['c'] = ((12 & 0x1F) << 2),
    ['8'] = (( 8 & 0x1F) << 2), ['d'] = ((13 & 0x1F) << 2),
    ['9'] = (( 9 & 0x1F) << 2), ['e'] = ((14 & 0x1F) << 2),
    ['A'] = ((10 & 0x1F) << 2), ['f'] = ((15 & 0x1F) << 2),
    ['B'] = ((11 & 0x1F) << 2), ['g'] = ((16 & 0x1F) << 2),
    ['C'] = ((12 & 0x1F) << 2), ['h'] = ((17 & 0x1F) << 2),
    ['D'] = ((13 & 0x1F) << 2), ['i'] = ((18 & 0x1F) << 2),
    ['E'] = ((14 & 0x1F) << 2), ['j'] = ((19 & 0x1F) << 2),
    ['F'] = ((15 & 0x1F) << 2), ['k'] = ((20 & 0x1F) << 2),
    ['G'] = ((16 & 0x1F) << 2), ['l'] = ((21 & 0x1F) << 2),
    ['H'] = ((17 & 0x1F) << 2), ['m'] = ((22 & 0x1F) << 2),
    ['I'] = ((18 & 0x1F) << 2), ['n'] = ((23 & 0x1F) << 2),
    ['J'] = ((19 & 0x1F) << 2), ['o'] = ((24 & 0x1F) << 2),
    ['K'] = ((20 & 0x1F) << 2), ['p'] = ((25 & 0x1F) << 2),
    ['L'] = ((21 & 0x1F) << 2), ['q'] = ((26 & 0x1F) << 2),
    ['M'] = ((22 & 0x1F) << 2), ['r'] = ((27 & 0x1F) << 2),
    ['N'] = ((23 & 0x1F) << 2), ['s'] = ((28 & 0x1F) << 2),
    ['O'] = ((24 & 0x1F) << 2), ['t'] = ((29 & 0x1F) << 2),
    ['P'] = ((25 & 0x1F) << 2), ['u'] = ((30 & 0x1F) << 2),
    ['Q'] = ((26 & 0x1F) << 2), ['v'] = ((31 & 0x1F) << 2),
};

// 0x18 = 00011000
const uint8_t seventh_left_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x18) >> 3), ['R'] = ((27 & 0x18) >> 3),
    ['1'] = (( 1 & 0x18) >> 3), ['S'] = ((28 & 0x18) >> 3),
    ['2'] = (( 2 & 0x18) >> 3), ['T'] = ((29 & 0x18) >> 3),
    ['3'] = (( 3 & 0x18) >> 3), ['U'] = ((30 & 0x18) >> 3),
    ['4'] = (( 4 & 0x18) >> 3), ['V'] = ((31 & 0x18) >> 3),
    ['5'] = (( 5 & 0x18) >> 3), ['a'] = ((10 & 0x18) >> 3),
    ['6'] = (( 6 & 0x18) >> 3), ['b'] = ((11 & 0x18) >> 3),
    ['7'] = (( 7 & 0x18) >> 3), ['c'] = ((12 & 0x18) >> 3),
    ['8'] = (( 8 & 0x18) >> 3), ['d'] = ((13 & 0x18) >> 3),
    ['9'] = (( 9 & 0x18) >> 3), ['e'] = ((14 & 0x18) >> 3),
    ['A'] = ((10 & 0x18) >> 3), ['f'] = ((15 & 0x18) >> 3),
    ['B'] = ((11 & 0x18) >> 3), ['g'] = ((16 & 0x18) >> 3),
    ['C'] = ((12 & 0x18) >> 3), ['h'] = ((17 & 0x18) >> 3),
    ['D'] = ((13 & 0x18) >> 3), ['i'] = ((18 & 0x18) >> 3),
    ['E'] = ((14 & 0x18) >> 3), ['j'] = ((19 & 0x18) >> 3),
    ['F'] = ((15 & 0x18) >> 3), ['k'] = ((20 & 0x18) >> 3),
    ['G'] = ((16 & 0x18) >> 3), ['l'] = ((21 & 0x18) >> 3),
    ['H'] = ((17 & 0x18) >> 3), ['m'] = ((22 & 0x18) >> 3),
    ['I'] = ((18 & 0x18) >> 3), ['n'] = ((23 & 0x18) >> 3),
    ['J'] = ((19 & 0x18) >> 3), ['o'] = ((24 & 0x18) >> 3),
    ['K'] = ((20 & 0x18) >> 3), ['p'] = ((25 & 0x18) >> 3),
    ['L'] = ((21 & 0x18) >> 3), ['q'] = ((26 & 0x18) >> 3),
    ['M'] = ((22 & 0x18) >> 3), ['r'] = ((27 & 0x18) >> 3),
    ['N'] = ((23 & 0x18) >> 3), ['s'] = ((28 & 0x18) >> 3),
    ['O'] = ((24 & 0x18) >> 3), ['t'] = ((29 & 0x18) >> 3),
    ['P'] = ((25 & 0x18) >> 3), ['u'] = ((30 & 0x18) >> 3),
    ['Q'] = ((26 & 0x18) >> 3), ['v'] = ((31 & 0x18) >> 3),
};

// 0x07 = 00000111
const uint8_t seventh_right_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x07) << 5), ['R'] = ((27 & 0x07) << 5),
    ['1'] = (( 1 & 0x07) << 5), ['S'] = ((28 & 0x07) << 5),
    ['2'] = (( 2 & 0x07) << 5), ['T'] = ((29 & 0x07) << 5),
    ['3'] = (( 3 & 0x07) << 5), ['U'] = ((30 & 0x07) << 5),
    ['4'] = (( 4 & 0x07) << 5), ['V'] = ((31 & 0x07) << 5),
    ['5'] = (( 5 & 0x07) << 5), ['a'] = ((10 & 0x07) << 5),
    ['6'] = (( 6 & 0x07) << 5), ['b'] = ((11 & 0x07) << 5),
    ['7'] = (( 7 & 0x07) << 5), ['c'] = ((12 & 0x07) << 5),
    ['8'] = (( 8 & 0x07) << 5), ['d'] = ((13 & 0x07) << 5),
    ['9'] = (( 9 & 0x07) << 5), ['e'] = ((14 & 0x07) << 5),
    ['A'] = ((10 & 0x07) << 5), ['f'] = ((15 & 0x07) << 5),
    ['B'] = ((11 & 0x07) << 5), ['g'] = ((16 & 0x07) << 5),
    ['C'] = ((12 & 0x07) << 5), ['h'] = ((17 & 0x07) << 5),
    ['D'] = ((13 & 0x07) << 5), ['i'] = ((18 & 0x07) << 5),
    ['E'] = ((14 & 0x07) << 5), ['j'] = ((19 & 0x07) << 5),
    ['F'] = ((15 & 0x07) << 5), ['k'] = ((20 & 0x07) << 5),
    ['G'] = ((16 & 0x07) << 5), ['l'] = ((21 & 0x07) << 5),
    ['H'] = ((17 & 0x07) << 5), ['m'] = ((22 & 0x07) << 5),
    ['I'] = ((18 & 0x07) << 5), ['n'] = ((23 & 0x07) << 5),
    ['J'] = ((19 & 0x07) << 5), ['o'] = ((24 & 0x07) << 5),
    ['K'] = ((20 & 0x07) << 5), ['p'] = ((25 & 0x07) << 5),
    ['L'] = ((21 & 0x07) << 5), ['q'] = ((26 & 0x07) << 5),
    ['M'] = ((22 & 0x07) << 5), ['r'] = ((27 & 0x07) << 5),
    ['N'] = ((23 & 0x07) << 5), ['s'] = ((28 & 0x07) << 5),
    ['O'] = ((24 & 0x07) << 5), ['t'] = ((29 & 0x07) << 5),
    ['P'] = ((25 & 0x07) << 5), ['u'] = ((30 & 0x07) << 5),
    ['Q'] = ((26 & 0x07) << 5), ['v'] = ((31 & 0x07) << 5),
};

// 0x1F = 00011111
const uint8_t eighth_base32hex_to_num[] = {
    ['0'] = (( 0 & 0x1F) << 0), ['R'] = ((27 & 0x1F) << 0),
    ['1'] = (( 1 & 0x1F) << 0), ['S'] = ((28 & 0x1F) << 0),
    ['2'] = (( 2 & 0x1F) << 0), ['T'] = ((29 & 0x1F) << 0),
    ['3'] = (( 3 & 0x1F) << 0), ['U'] = ((30 & 0x1F) << 0),
    ['4'] = (( 4 & 0x1F) << 0), ['V'] = ((31 & 0x1F) << 0),
    ['5'] = (( 5 & 0x1F) << 0), ['a'] = ((10 & 0x1F) << 0),
    ['6'] = (( 6 & 0x1F) << 0), ['b'] = ((11 & 0x1F) << 0),
    ['7'] = (( 7 & 0x1F) << 0), ['c'] = ((12 & 0x1F) << 0),
    ['8'] = (( 8 & 0x1F) << 0), ['d'] = ((13 & 0x1F) << 0),
    ['9'] = (( 9 & 0x1F) << 0), ['e'] = ((14 & 0x1F) << 0),
    ['A'] = ((10 & 0x1F) << 0), ['f'] = ((15 & 0x1F) << 0),
    ['B'] = ((11 & 0x1F) << 0), ['g'] = ((16 & 0x1F) << 0),
    ['C'] = ((12 & 0x1F) << 0), ['h'] = ((17 & 0x1F) << 0),
    ['D'] = ((13 & 0x1F) << 0), ['i'] = ((18 & 0x1F) << 0),
    ['E'] = ((14 & 0x1F) << 0), ['j'] = ((19 & 0x1F) << 0),
    ['F'] = ((15 & 0x1F) << 0), ['k'] = ((20 & 0x1F) << 0),
    ['G'] = ((16 & 0x1F) << 0), ['l'] = ((21 & 0x1F) << 0),
    ['H'] = ((17 & 0x1F) << 0), ['m'] = ((22 & 0x1F) << 0),
    ['I'] = ((18 & 0x1F) << 0), ['n'] = ((23 & 0x1F) << 0),
    ['J'] = ((19 & 0x1F) << 0), ['o'] = ((24 & 0x1F) << 0),
    ['K'] = ((20 & 0x1F) << 0), ['p'] = ((25 & 0x1F) << 0),
    ['L'] = ((21 & 0x1F) << 0), ['q'] = ((26 & 0x1F) << 0),
    ['M'] = ((22 & 0x1F) << 0), ['r'] = ((27 & 0x1F) << 0),
    ['N'] = ((23 & 0x1F) << 0), ['s'] = ((28 & 0x1F) << 0),
    ['O'] = ((24 & 0x1F) << 0), ['t'] = ((29 & 0x1F) << 0),
    ['P'] = ((25 & 0x1F) << 0), ['u'] = ((30 & 0x1F) << 0),
    ['Q'] = ((26 & 0x1F) << 0), ['v'] = ((31 & 0x1F) << 0),
};

// Without leap day 29. 2.
static const uint8_t days_in_months[] = {
    [ 1] = 31, [ 2] = 28, [ 3] = 31, [ 4] = 30, [ 5] = 31, [ 6] = 30,
    [ 7] = 31, [ 8] = 31, [ 9] = 30, [10] = 31, [11] = 30, [12] = 31,
};

// Without leap day 29. 2.
static const uint16_t days_across_months[] = {
    [ 1] =   0, [ 2] =  31, [ 3] =  59, [ 4] =  90, [ 5] = 120, [ 6] = 151,
    [ 7] = 181, [ 8] = 212, [ 9] = 243, [10] = 273, [11] = 304, [12] = 334,
};

// 0 ~ 1970 ... 135 ~ 2105 ... 255 ~ 2225
static const uint8_t is_leap_year[] = {
    [  1] = 0, [  2] = 1, [  3] = 0, [  4] = 0, [  5] = 0,
    [  6] = 1, [  7] = 0, [  8] = 0, [  9] = 0, [ 10] = 1,
    [ 11] = 0, [ 12] = 0, [ 13] = 0, [ 14] = 1, [ 15] = 0,
    [ 16] = 0, [ 17] = 0, [ 18] = 1, [ 19] = 0, [ 20] = 0,
    [ 21] = 0, [ 22] = 1, [ 23] = 0, [ 24] = 0, [ 25] = 0,
    [ 26] = 1, [ 27] = 0, [ 28] = 0, [ 29] = 0, [ 30] = 1,
    [ 31] = 0, [ 32] = 0, [ 33] = 0, [ 34] = 1, [ 35] = 0,
    [ 36] = 0, [ 37] = 0, [ 38] = 1, [ 39] = 0, [ 40] = 0,
    [ 41] = 0, [ 42] = 1, [ 43] = 0, [ 44] = 0, [ 45] = 0,
    [ 46] = 1, [ 47] = 0, [ 48] = 0, [ 49] = 0, [ 50] = 1,
    [ 51] = 0, [ 52] = 0, [ 53] = 0, [ 54] = 1, [ 55] = 0,
    [ 56] = 0, [ 57] = 0, [ 58] = 1, [ 59] = 0, [ 60] = 0,
    [ 61] = 0, [ 62] = 1, [ 63] = 0, [ 64] = 0, [ 65] = 0,
    [ 66] = 1, [ 67] = 0, [ 68] = 0, [ 69] = 0, [ 70] = 1,
    [ 71] = 0, [ 72] = 0, [ 73] = 0, [ 74] = 1, [ 75] = 0,
    [ 76] = 0, [ 77] = 0, [ 78] = 1, [ 79] = 0, [ 80] = 0,
    [ 81] = 0, [ 82] = 1, [ 83] = 0, [ 84] = 0, [ 85] = 0,
    [ 86] = 1, [ 87] = 0, [ 88] = 0, [ 89] = 0, [ 90] = 1,
    [ 91] = 0, [ 92] = 0, [ 93] = 0, [ 94] = 1, [ 95] = 0,
    [ 96] = 0, [ 97] = 0, [ 98] = 1, [ 99] = 0, [100] = 0,
    [101] = 0, [102] = 1, [103] = 0, [104] = 0, [105] = 0,
    [106] = 1, [107] = 0, [108] = 0, [109] = 0, [110] = 1,
    [111] = 0, [112] = 0, [113] = 0, [114] = 1, [115] = 0,
    [116] = 0, [117] = 0, [118] = 1, [119] = 0, [120] = 0,
    [121] = 0, [122] = 1, [123] = 0, [124] = 0, [125] = 0,
    [126] = 1, [127] = 0, [128] = 0, [129] = 0, [130] = 0,
    [131] = 0, [132] = 0, [133] = 0, [134] = 1, [135] = 0,
    [136] = 0, [137] = 0, [138] = 1, [139] = 0, [140] = 0,
    [141] = 0, [142] = 1, [143] = 0, [144] = 0, [145] = 0,
    [146] = 1, [147] = 0, [148] = 0, [149] = 0, [150] = 1,
    [151] = 0, [152] = 0, [153] = 0, [154] = 1, [155] = 0,
    [156] = 0, [157] = 0, [158] = 1, [159] = 0, [160] = 0,
    [161] = 0, [162] = 1, [163] = 0, [164] = 0, [165] = 0,
    [166] = 1, [167] = 0, [168] = 0, [169] = 0, [170] = 1,
    [171] = 0, [172] = 0, [173] = 0, [174] = 1, [175] = 0,
    [176] = 0, [177] = 0, [178] = 1, [179] = 0, [180] = 0,
    [181] = 0, [182] = 1, [183] = 0, [184] = 0, [185] = 0,
    [186] = 1, [187] = 0, [188] = 0, [189] = 0, [190] = 1,
    [191] = 0, [192] = 0, [193] = 0, [194] = 1, [195] = 0,
    [196] = 0, [197] = 0, [198] = 1, [199] = 0, [200] = 0,
    [201] = 0, [202] = 1, [203] = 0, [204] = 0, [205] = 0,
    [206] = 1, [207] = 0, [208] = 0, [209] = 0, [210] = 1,
    [211] = 0, [212] = 0, [213] = 0, [214] = 1, [215] = 0,
    [216] = 0, [217] = 0, [218] = 1, [219] = 0, [220] = 0,
    [221] = 0, [222] = 1, [223] = 0, [224] = 0, [225] = 0,
    [226] = 1, [227] = 0, [228] = 0, [229] = 0, [230] = 0,
    [231] = 0, [232] = 0, [233] = 0, [234] = 1, [235] = 0,
    [236] = 0, [237] = 0, [238] = 1, [239] = 0, [240] = 0,
    [241] = 0, [242] = 1, [243] = 0, [244] = 0, [245] = 0,
    [246] = 1, [247] = 0, [248] = 0, [249] = 0, [250] = 1,
    [251] = 0, [252] = 0, [253] = 0, [254] = 1, [255] = 0,
};

// 0 ~ 1970 ... 135 ~ 2105 ... 255 ~ 2225
static const uint32_t days_across_years[] = {
    [  1] =   365, [  2] =   730, [  3] =  1096, [  4] =  1461, [  5] =  1826,
    [  6] =  2191, [  7] =  2557, [  8] =  2922, [  9] =  3287, [ 10] =  3652,
    [ 11] =  4018, [ 12] =  4383, [ 13] =  4748, [ 14] =  5113, [ 15] =  5479,
    [ 16] =  5844, [ 17] =  6209, [ 18] =  6574, [ 19] =  6940, [ 20] =  7305,
    [ 21] =  7670, [ 22] =  8035, [ 23] =  8401, [ 24] =  8766, [ 25] =  9131,
    [ 26] =  9496, [ 27] =  9862, [ 28] = 10227, [ 29] = 10592, [ 30] = 10957,
    [ 31] = 11323, [ 32] = 11688, [ 33] = 12053, [ 34] = 12418, [ 35] = 12784,
    [ 36] = 13149, [ 37] = 13514, [ 38] = 13879, [ 39] = 14245, [ 40] = 14610,
    [ 41] = 14975, [ 42] = 15340, [ 43] = 15706, [ 44] = 16071, [ 45] = 16436,
    [ 46] = 16801, [ 47] = 17167, [ 48] = 17532, [ 49] = 17897, [ 50] = 18262,
    [ 51] = 18628, [ 52] = 18993, [ 53] = 19358, [ 54] = 19723, [ 55] = 20089,
    [ 56] = 20454, [ 57] = 20819, [ 58] = 21184, [ 59] = 21550, [ 60] = 21915,
    [ 61] = 22280, [ 62] = 22645, [ 63] = 23011, [ 64] = 23376, [ 65] = 23741,
    [ 66] = 24106, [ 67] = 24472, [ 68] = 24837, [ 69] = 25202, [ 70] = 25567,
    [ 71] = 25933, [ 72] = 26298, [ 73] = 26663, [ 74] = 27028, [ 75] = 27394,
    [ 76] = 27759, [ 77] = 28124, [ 78] = 28489, [ 79] = 28855, [ 80] = 29220,
    [ 81] = 29585, [ 82] = 29950, [ 83] = 30316, [ 84] = 30681, [ 85] = 31046,
    [ 86] = 31411, [ 87] = 31777, [ 88] = 32142, [ 89] = 32507, [ 90] = 32872,
    [ 91] = 33238, [ 92] = 33603, [ 93] = 33968, [ 94] = 34333, [ 95] = 34699,
    [ 96] = 35064, [ 97] = 35429, [ 98] = 35794, [ 99] = 36160, [100] = 36525,
    [101] = 36890, [102] = 37255, [103] = 37621, [104] = 37986, [105] = 38351,
    [106] = 38716, [107] = 39082, [108] = 39447, [109] = 39812, [110] = 40177,
    [111] = 40543, [112] = 40908, [113] = 41273, [114] = 41638, [115] = 42004,
    [116] = 42369, [117] = 42734, [118] = 43099, [119] = 43465, [120] = 43830,
    [121] = 44195, [122] = 44560, [123] = 44926, [124] = 45291, [125] = 45656,
    [126] = 46021, [127] = 46387, [128] = 46752, [129] = 47117, [130] = 47482,
    [131] = 47847, [132] = 48212, [133] = 48577, [134] = 48942, [135] = 49308,
    [136] = 49673, [137] = 50038, [138] = 50403, [139] = 50769, [140] = 51134,
    [141] = 51499, [142] = 51864, [143] = 52230, [144] = 52595, [145] = 52960,
    [146] = 53325, [147] = 53691, [148] = 54056, [149] = 54421, [150] = 54786,
    [151] = 55152, [152] = 55517, [153] = 55882, [154] = 56247, [155] = 56613,
    [156] = 56978, [157] = 57343, [158] = 57708, [159] = 58074, [160] = 58439,
    [161] = 58804, [162] = 59169, [163] = 59535, [164] = 59900, [165] = 60265,
    [166] = 60630, [167] = 60996, [168] = 61361, [169] = 61726, [170] = 62091,
    [171] = 62457, [172] = 62822, [173] = 63187, [174] = 63552, [175] = 63918,
    [176] = 64283, [177] = 64648, [178] = 65013, [179] = 65379, [180] = 65744,
    [181] = 66109, [182] = 66474, [183] = 66840, [184] = 67205, [185] = 67570,
    [186] = 67935, [187] = 68301, [188] = 68666, [189] = 69031, [190] = 69396,
    [191] = 69762, [192] = 70127, [193] = 70492, [194] = 70857, [195] = 71223,
    [196] = 71588, [197] = 71953, [198] = 72318, [199] = 72684, [200] = 73049,
    [201] = 73414, [202] = 73779, [203] = 74145, [204] = 74510, [205] = 74875,
    [206] = 75240, [207] = 75606, [208] = 75971, [209] = 76336, [210] = 76701,
    [211] = 77067, [212] = 77432, [213] = 77797, [214] = 78162, [215] = 78528,
    [216] = 78893, [217] = 79258, [218] = 79623, [219] = 79989, [220] = 80354,
    [221] = 80719, [222] = 81084, [223] = 81450, [224] = 81815, [225] = 82180,
    [226] = 82545, [227] = 82911, [228] = 83276, [229] = 83641, [230] = 84006,
    [231] = 84371, [232] = 84736, [233] = 85101, [234] = 85466, [235] = 85832,
    [236] = 86197, [237] = 86562, [238] = 86927, [239] = 87293, [240] = 87658,
    [241] = 88023, [242] = 88388, [243] = 88754, [244] = 89119, [245] = 89484,
    [246] = 89849, [247] = 90215, [248] = 90580, [249] = 90945, [250] = 91310,
    [251] = 91676, [252] = 92041, [253] = 92406, [254] = 92771, [255] = 93137,
};

int date_to_timestamp(uint8_t *buff, uint32_t *timestamp)
{
	uint32_t year, month, day, hour, minute, second;
	uint32_t leap_day = 0;

	year   = 1000 * (buff[ 0] - '0') + 100 * (buff[ 1] - '0') +
	           10 * (buff[ 2] - '0') +       (buff[ 3] - '0');
	month  =   10 * (buff[ 4] - '0') +       (buff[ 5] - '0');
	day    =   10 * (buff[ 6] - '0') +       (buff[ 7] - '0');
	hour   =   10 * (buff[ 8] - '0') +       (buff[ 9] - '0');
	minute =   10 * (buff[10] - '0') +       (buff[11] - '0');
	second =   10 * (buff[12] - '0') +       (buff[13] - '0');

	if (year < 1970 || year > 2225 || month < 1 || month > 12 || day < 1) {
		return ZS_BAD_DATE;
	} else {
		year -= 1970;
	}

	if (is_leap_year[year]) {
		if (month > 2) {
			leap_day = 1; // Add one day in case of leap year.
		} else if (month == 2 &&
		           day > (uint32_t)(days_in_months[month] + 1)) {
			return ZS_BAD_DATE;
		}
	} else if (day > days_in_months[month]){
		return ZS_BAD_DATE;
	}

	if (hour > 23 || minute > 59 || second > 59) {
		return ZS_BAD_TIME;
	}

	*timestamp = hour * 3600 + minute * 60 + second +
	             (days_across_years[year] +
	             days_across_months[month] +
	             day - 1 + leap_day) * 86400;

	return ZS_OK;
}

void wire_dname_to_str(const uint8_t  *data,
                       const uint32_t data_len,
                       char           *text)
{
	uint32_t i = 0, text_len = 0;

	if (data == NULL || data_len == 0 || text == NULL) {
		return;
	}

	uint8_t label_len = data[0];

	// Loop over data characters.
	for (i = 1; i < data_len; i++) {
		// Replace label length with dot.
		if (label_len == 0) {
			label_len = data[i];
			text[text_len++] = '.';
			continue;
		}

		// Just in case use \123 notation.
		text[text_len++] = '\\';
		text[text_len++] = (data[i] / 100)      + '0';
		text[text_len++] = (data[i] /  10) % 10 + '0';
		text[text_len++] = (data[i]      ) % 10 + '0';

		label_len--;
	}

	// Add trailing dot for root domain.
	if (data_len == 1 && label_len == 0) {
		text[text_len++] = '.';
	}

	// Ending text string.
	text[text_len] = 0;
}

uint8_t loc64to8(uint64_t number)
{
	uint8_t exponent = 0;

	while (number > 9) {
		number /= 10;
		exponent++;
	}
	// First 4 bits are mantisa, second 4 bits are exponent.
	return ((uint8_t)number << 4) + (exponent & 15);
}

static int mandatory_cmp(const void *p1, const void *p2)
{
	uint16_t val1, val2;
	memcpy(&val1, p1, sizeof(val1));
	memcpy(&val2, p2, sizeof(val2));

	if (be16toh(val1) < be16toh(val2)) {
		return -1;
	} else if (val1 == val2) {
		return 0;
	} else {
		return 1;
	}
}

void svcb_mandatory_sort(uint8_t *list_begin, uint8_t *list_end)
{
	uint32_t count = (list_end - list_begin) / sizeof(uint16_t);
	qsort(list_begin, count, sizeof(uint16_t), mandatory_cmp);
}

int svcb_sort(zs_scanner_t *scanner, uint8_t *rdata_end)
{
	zs_svcb_t *svcb = &(scanner->svcb);

	uint8_t *curr_pos = svcb->param_position;

	uint16_t curr_key;
	memcpy(&curr_key, curr_pos, sizeof(uint16_t));
	curr_key = be16toh(curr_key);

	if (curr_key > svcb->last_key) {
		// Already sorted.
		svcb->last_key = curr_key;
		return ZS_OK;
	}

	uint8_t *param_pos = svcb->params_position;
	while (param_pos < curr_pos) {
		uint16_t param_key, param_len;
		memcpy(&param_key, param_pos, 2);
		param_key = be16toh(param_key);
		memcpy(&param_len, param_pos + sizeof(uint16_t), 2);
		param_len = be16toh(param_len);

		uint32_t param_full_len = 2 * sizeof(uint16_t) + param_len;

		if (curr_key < param_key) {
			uint32_t curr_full_len = rdata_end - curr_pos;
			memcpy(scanner->buffer, curr_pos, curr_full_len);
			memmove(param_pos + curr_full_len, param_pos,
			        curr_pos - param_pos);
			memcpy(param_pos, scanner->buffer, curr_full_len);
			break;
		} else if (curr_key == param_key) {
			return ZS_DUPLICATE_SVCB_KEY;
		}

		param_pos += param_full_len;
	}

	return ZS_OK;
}

int svcb_check(zs_scanner_t *scanner, uint8_t *rdata_end)
{
	zs_svcb_t *svcb = &(scanner->svcb);

	if (svcb->params_position == rdata_end ||
	    svcb->params_position[0] != 0 || svcb->params_position[1] != 0) {
		return ZS_OK; // No parameters or no mandatory parameter available.
	}

	uint16_t mandat_size;
	memcpy(&mandat_size, svcb->params_position + sizeof(uint16_t), sizeof(uint16_t));
	mandat_size = be16toh(mandat_size);

	uint16_t mandat_count = mandat_size / sizeof(uint16_t);

	uint8_t *param_pos = svcb->params_position + 2 * sizeof(uint16_t) + mandat_size;
	const uint8_t *mandats = svcb->params_position + 2 * sizeof(uint16_t);
	for (int i = 0; i < mandat_count; i++) {
		// Check for duplicates.
		if (i > 0 && memcmp(mandats + (i - 1) * sizeof(uint16_t),
		                    mandats + i * sizeof(uint16_t), 2) == 0) {
			return ZS_DUPLICATE_SVCB_MANDATORY;
		}

		bool found = false;
		while (param_pos < rdata_end && !found) {
			uint16_t param_key, param_len;
			memcpy(&param_key, param_pos, 2);
			memcpy(&param_len, param_pos + sizeof(uint16_t), 2);
			param_len = be16toh(param_len);

			// Compare keys in big endian.
			if (memcmp(mandats + i * sizeof(uint16_t), param_pos, 2) == 0) {
				found = true;
			}
			param_pos += 2 * sizeof(uint16_t) + param_len;
		}
		if (!found) {
			return ZS_MISSING_SVCB_MANDATORY;
		}
	}

	return ZS_OK;
}
